
#include <xbi/xbi.h>

#include <getopt.h>

int main(int argc, char * argv[]) {
    
    XBISecuritySector * ss = NULL;
    char * ssPath = NULL;
    FILE * ssFile = NULL;
    XBIDiskManufacturingInformation * dmi = NULL;
    char * dmiPath = NULL;
    FILE * dmiFile = NULL;
    XBIPhysicalFormatInformation * pfi = NULL;
    char * pfiPath = NULL;
    FILE * pfiFile = NULL;
    XBIIntroVideoHalf * firstVideoHalf = NULL;
    XBIIntroVideoHalf * secondVideoHalf = NULL;
    char * videoPath = NULL;
    FILE * videoFile = NULL;
    
    XBIImage * image = NULL;
    char * imagePath = NULL;
    FILE * imageFile = NULL;
    
    XBIError error;
    
    int ch;
    
    /* options descriptor */
    static struct option longopts[] = {
        { "security-sector",                required_argument, NULL, 's' },
        { "disk-manufacturing-information", required_argument, NULL, 'd' },
        { "physical-format-information",    required_argument, NULL, 'p' },
        { "video",                          required_argument, NULL, 'v' },
        { NULL,                             0,                 NULL,  0  }
    };

    if (argc < 2) {
        printf("Usage : xbi [--security-sector SS.bin] [--disk-manufacturing-information DMI.bin] [--physical-format-information PFI.bin] [--video video.iso] xbox_iso_file.iso\n");
        return -1;
    }
    
    while ((ch = getopt_long(argc, argv, "s:d:p:v:", longopts, NULL)) != -1) {
        switch (ch) {
            case 's':
                ssPath = optarg;
                break;
            case 'd':
                dmiPath = optarg;
                break;
            case 'p':
                pfiPath = optarg;
                break;
            case 'v':
                videoPath = optarg;
                break;
            default:
                printf("Unexpected option\n");
                return -1;
        }
    }
    argc -= optind;
    argv += optind;
    
    XBIAssert(argc == 1, "Wrong number of arguments\n");
    
    imagePath = argv[0];

    XBIAssert(imagePath != NULL, "Bad arguments\n");
    
    if (ssPath == NULL && dmiPath == NULL && pfiPath == NULL && videoPath == NULL) {
        XBILog("Opening %s read-only\n", imagePath);
        imageFile = fopen(imagePath, "r"); // Readonly
    } else {
        XBILog("Opening %s read-write\n", imagePath);
        imageFile = fopen(imagePath, "r+");
    }

    image = XBIImageCreateFromFile(imageFile, &error);        
    if (image == NULL)
        goto error;

    if (ssPath != NULL) {
        ssFile = fopen(ssPath, "r");
        if (ssFile != NULL) {
            ss = XBISSCreateFromFile(ssFile, &error);
            fclose(ssFile);
            if (ss == NULL) {
                printf("Error loading SS\n");
                goto error;
            }
        }
    }

    if (dmiPath != NULL) {
        dmiFile = fopen(dmiPath, "r");
        if (dmiFile != NULL) {
            dmi = XBIDMICreateFromFile(dmiFile, &error);
            fclose(dmiFile);
            if (dmi == NULL) {
                XBILog("Error loading DMI\n");
                goto error;
            }
        }
    }

    if (pfiPath != NULL) {
        pfiFile = fopen(pfiPath, "r");
        if (pfiFile != NULL) {
            pfi = XBIPFICreateFromFile(kXBIPFIXbox360Version, pfiFile, &error);
            fclose(pfiFile);
            if (pfi == NULL) {
                XBILog("Error loading PFI\n");
                goto error;
            }
        }
    }
    

    if (videoPath != NULL) {
        videoFile = fopen(videoPath, "r");
        if (videoFile != NULL) {
            XBILoadVideoFromFile(videoFile, &firstVideoHalf, &secondVideoHalf, &error);
            fclose(videoFile);
            if (firstVideoHalf == NULL || secondVideoHalf == NULL) {
                XBILog("Error loading video\n");
                goto error;
            }
        }
    }
    
    XBILog("--------- FINISHED PARSING ---------\n");
    
    XBILog("Ultimately, ISO is Stealth ? %s\n", XBIImageIsStealthPatched(image) ? "YES" : "NO");
    
    XBIXboxEXecutable * defaultXEX = XBIImageGetDefaultXEX(image, &error);
    XBILog("Final CRCs :\n");
    XBILog("default.xex = 0x%X\n", XBIXEXGetCRC32(defaultXEX));
    XBILog("DMI = 0x%X\n", XBIDMIGetCRC32(XBIImageGetDMI(image)));
    XBILog("PFI = 0x%X\n", XBIPFIGetCRC32(XBIImageGetPFI(image)));
    XBILog("SS = 0x%X\n", XBISSGetCRC32(XBIImageGetSS(image)));
        
    XBILog("PFI : DiscSize = %lld (%d + %d)\n", XBIPFIGetDiscSize(XBIImageGetPFI(image)), XBIPFIGetLayer0SizeInSectors(XBIImageGetPFI(image)), XBIPFIGetLayer1SizeInSectors(XBIImageGetPFI(image)));

    if (ss) {
        if (XBIImageSetSS(image, ss, &error) == 0) {
            XBILog("Security sector correctly written !\n");
        } else {
            XBILog("Error: Couldn't write Security Sector !\n");
        }
    }
    
    if (dmi) {        
        if (XBIImageSetDMI(image, dmi, &error) == 0) {
            XBILog("DMI correctly written !\n");
        } else {
            XBILog("Error: Couldn't write DMI !\n");
        }
    }

    if (pfi) {
        if (XBIImageSetPFI(image, pfi, &error) == 0) {
            XBILog("PFI correctly written !\n");
        } else {
            XBILog("Error: Couldn't write PFI !\n");
        }
    }
    
    if (firstVideoHalf) {
        if (XBIImageSetFirstIVH(image, firstVideoHalf, &error) == 0) {
            XBILog("First video half correctly written !\n");
        } else {
            XBILog("Error: Couldn't write first video half !\n");
        }        
    }

    if (secondVideoHalf) {
        if (XBIImageSetSecondIVH(image, secondVideoHalf, &error) == 0) {
            XBILog("Second video half correctly written !\n");
        } else {
            XBILog("Error: Couldn't write second video half !\n");
        }        
    }
    
error:
    XBIImageDelete(image);    
    fclose(imageFile);
    return 0;
}
